Skip to content

Refactor provider dispatch behind a Backend trait#32

Closed
bddap-bot wants to merge 2 commits into
bddap:mainfrom
bddap-bot:backend-trait
Closed

Refactor provider dispatch behind a Backend trait#32
bddap-bot wants to merge 2 commits into
bddap:mainfrom
bddap-bot:backend-trait

Conversation

@bddap-bot

Copy link
Copy Markdown
Contributor

PR A of the two-PR plan in #31: a pure refactor that introduces a common provider interface, no behavior change. PR B (function-call edits, the #31 rewrite) stacks on this.

What

main.rs::refactor() matched on Provider, re-derived the API key inline, and called a free anthropic::complete / openai::complete. That match-and-duplicate is exactly what gets ugly when a second call shape (tool edits) lands.

  • New src/backend.rs: trait Backend { fn complete(&self, &[Message]) -> Result<String>; } and resolve(provider, model, &secrets) -> Result<Box<dyn Backend>> — the one place that knows how each provider sources its key and errors when it's missing.
  • anthropic.rs / openai.rs each gain an Anthropic / Openai struct that impl Backend, forwarding to the (now private) send() wire call.
  • refactor() collapses to backend::resolve(provider, &model, sc)?.complete(&messages).

Why Box<dyn Backend> and not a closed enum

Tool/function-call edits (PR B) are Anthropic-only. A trait expresses that as a separate Edits trait that only Anthropic implements — no enum arm faking "unsupported" at runtime. Documented in backend.rs.

No behavior change

Wire formats untouched. The "no key" trigger conditions and messages are byte-identical (moved verbatim into resolve). Provider/model resolution unchanged.

Tests

cargo test → 7 passing (the 5 existing + 2 new resolve tests covering missing-key and present-key for both providers). clippy clean on the changed files. Built with nixpkgs rust 1.91.

Self-reviewed via two rounds of fan-out review agents (correctness, security, Niko-style design): no correctness/security findings; applied the design refinements (borrow model, rename the private wire fn to send, document the dyn choice).

🤖 Generated with Claude Code

main.rs::refactor() matched on Provider, re-derived the API key inline, and
called a free anthropic::complete / openai::complete — a match-and-duplicate
that grows worse with each new call shape. Introduce a Backend trait and a
single resolve() that turns a provider choice into a key-bearing, callable
backend, so the rest of refac stays provider-agnostic.

No behavior change: wire formats, error paths, and "no key" messages are
identical. Paves the way for an Anthropic-only tool/edit capability (a separate
trait, hence Box<dyn Backend> over a closed enum).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…only

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@bddap-bot

Copy link
Copy Markdown
Contributor Author

Obsoleted by #33. #33 cuts the whole-text rewrite path entirely (owner's call — personal tool, no need to keep it), so the Backend-trait refactor this PR introduced for the rewrite dispatch is moot. The edit-mode work lives in #33, which now stands alone.

@bddap-bot bddap-bot closed this Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant